module ActsAsDynamic::SuperFind

  def set_qualifiers(options = {})
    @qualifiers = options
    @sp = SearchParser.new(@qualifiers.keys.reject{|q| q == :unqualif})
  end

  def super_find(qs)
    find(:all, super_find_options(qs))
  end
  
  def super_find_options(qs)
    opts = @sp.parse(qs)
    fnd_opts = {}
    includes = []
    cond_str = []
    cond_params = []
    opts.keys.map(&:to_s).sort.each do |q|
      qualif = q.to_sym
      value = opts[qualif]
      dfn = @qualifiers[qualif]
      unless qualif == :unqualif && value.empty?
        fld = get_qs_field(qualif)
        str, params = get_qs_condition(fld, value, dfn)
        cond_str << str
        cond_params << params
        if dfn.is_a?(Hash) && dfn[:include]
          includes << dfn[:include]
        end
      end
    end
    fnd_opts[:conditions] = [cond_str.join(' AND '), cond_params].flatten
    fnd_opts[:include] = includes unless includes.empty?
    fnd_opts
  end
  
  def get_qs_field(qualif)
    dfn = @qualifiers[qualif]
    dfn.is_a?(String) ? dfn : dfn[:field]
  end
  
  def get_qs_condition(fld, value, dfn)
    comp = get_qs_comp(dfn)
    if dfn.is_a?(String) || comp == :like
      values = /^\[(.*)\]$/ =~ value ? $1.split(',') : [value]
      likes = values.map{|_| "LOWER(#{fld}) LIKE ?"}.join(' OR ')
      result = [values.size > 1 ? "(#{likes})" : likes]
      result << values.map {|v| "%#{v.downcase}%"}
      result
    else
      ["#{fld} #{get_qs_str_comp(comp)} ?", get_qs_value(dfn, value)]
    end
  end
  
  def get_qs_comp(dfn)
    dfn.is_a?(Hash) ? (dfn[:comp] || :like) : :like
  end
  
  def get_qs_str_comp(comp)
    case comp
      when :equal
        '='
      when :lt
        '<'
      when :le
        '<='
      when :gt
        '>'
      when :ge
        '>='
    end
  end
  
  def get_qs_value(dfn, value)
    rtn = nil
    if dfn[:magic] && (magic_value = dfn[:magic][value])
      rtn = magic_value.is_a?(Proc) ? magic_value.call(value) : magic_value
    end
    rtn || value
  end

end

ActiveRecord::Base.extend ActsAsDynamic::SuperFind
